package org.custom.spring.boot.security.application.http;

import lombok.Getter;
import org.cleaver.spring.utils.servlet.ServletUtil;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

/**
 * HttpServlet 请求体流信息包装类
 * <p>
 * 注：被此类包装的流信息支持多次读取
 *
 * @author LiKun
 */
public final class ServletRequestWrapper extends HttpServletRequestWrapper {

    private byte[] bytes;
    @Getter
    private String requestBody;

    private ServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        this.setBytes(RequestServletUtil.getRequestBody(request));
    }

    public static ServletRequestWrapper getInstance(HttpServletRequest request) throws IOException {
        if (request instanceof ServletRequestWrapper) {
            return (ServletRequestWrapper) request;
        } else {
            return new ServletRequestWrapper(request);
        }
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() {
        // 巨坑；此处不能直接在 read() 方法中创建 ByteArrayInputStream，否则读取时会创建无数个 ByteArrayInputStream；
        final ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);

        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public int read() {
                return inputStream.read();
            }

            @Override
            public void setReadListener(ReadListener readListener) {
            }
        };
    }

    /*-------------------------------------------------private methods------------------------------------------------*/

    /**
     * 设置 requestBody
     *
     * @param body 请求体
     */
    private void setBytes(String body) {
        this.requestBody = body;
        this.bytes = body.getBytes(StandardCharsets.UTF_8);
    }


    /*--------------------------------------------------static class--------------------------------------------------*/


    private final static class RequestServletUtil {
        /**
         * 读取 HttpServletRequest 中的请求体数据
         *
         * @param request 请求对象
         *
         * @return 请求体
         */
        public static String getRequestBody(HttpServletRequest request) throws IOException {
            if (request instanceof ServletRequestWrapper) {
                return ((ServletRequestWrapper) request).getRequestBody();
            } else {
                return ServletUtil.getServletRequestBody(request);
            }
        }
    }
}